這幾天分享了prompt的基本架構、要不要給範例、推理引導的用法,但以上用法都是主觀上認為有用,沒有一個明確的標準可以判斷模型回應是否變好、變得更符合需求。因此今天要講的主題,就是對於prompt「演進」的管理與除錯。
寫程式時,不會把邏輯改動直接蓋掉舊版本,而是用 git 留下紀錄、方便回頭比較。Prompt也適用這種方法,尤其當一個 prompt 牽涉到多個規則、範例、格式要求時,一次調整可能會在改善某個情境的同時,悄悄搞砸另一個情境。
版控實務上常見的做法:
以下用一個情緒分類的例子示範:同一組 test case,分別套用兩個版本的 system prompt,跑完後直接看誰的正確率比較高。
import os
import anthropic
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
test_cases = [
{"input": "出貨超快,包裝也很仔細,下次還會再買", "expected": "正面"},
{"input": "客服完全不讀訊息,等了三天才回,爛透了", "expected": "負面"},
{"input": "東西還行,沒有特別驚艷", "expected": "中立"},
{"input": "還可以啦,但價格偏貴", "expected": "中立"},
{"input": "品質普通,但至少準時送達,沒有太大問題", "expected": "中立"},
]
prompt_versions = {
"v1": "請判斷評論的情緒,只回傳「正面」「負面」或「中立」其中一個詞。",
"v2": (
"你是情緒分析助理。請判斷以下評論的整體情緒傾向。\n"
"規則:\n"
"- 只有明確偏好或不滿時才判斷為「正面」或「負面」\n"
"- 語氣平淡、有褒有貶、或無法判斷時一律回傳「中立」\n"
"只回傳「正面」「負面」或「中立」其中一個詞,不要加任何標點或說明。"
),
}
def run_prompt(system_prompt, user_input):
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=10,
temperature=0,
system=system_prompt,
messages=[{"role": "user", "content": user_input}],
)
return response.content[0].text.strip().strip("。.,、")
def evaluate(version_name, system_prompt):
correct = 0
print(f"\n=== 版本:{version_name} ===")
for case in test_cases:
result = run_prompt(system_prompt, case["input"])
is_correct = result == case["expected"]
correct += is_correct
mark = "✓" if is_correct else "✗"
print(f"{mark} 輸入:{case['input']} → 得到:{result}(預期:{case['expected']})")
accuracy = correct / len(test_cases)
print(f"正確率:{correct}/{len(test_cases)}({accuracy:.0%})")
return accuracy
results = {name: evaluate(name, prompt) for name, prompt in prompt_versions.items()}
print("\n=== 版本比較 ===")
for name, acc in results.items():
print(f"{name}: {acc:.0%}")
跑完之後可以直接看到兩個版本各自的正確率。如果 v2 在「中立」案例上明顯進步,同時沒有讓「正面」「負面」的判斷變差,就代表這次調整是確實有效的改善。
除了量化比較版本優劣,寫 prompt 時也有幾個比較常見雷點,越早避開,有機會能降低version 迭代的次數
在設計prompt時,常遇到的問題:
指令太模糊:例如只說「幫我整理一下」,沒定義格式、長度、重點,模型只好自由發揮,每次結果都不太一樣。可以透過把目標、預期結果與內容定義清楚,或直接透過structured output鎖定回應格式來解決。
prompt 太長,重點被稀釋:塞了太多規則跟背景資訊,模型可能會抓不住重點。解法是精簡、把最重要的規則放在最前面或最後面(模型對開頭跟結尾的內容通常比中間的更敏感)。
範例不具代表性:few-shot 範例都集中在某種情況,模型看到範例外的情況容易誤判。
使用者輸入跟系統指令混在一起:如果你把使用者輸入直接原封不動貼進 prompt,使用者有機會用輸入內容「蓋掉」你原本的指令(例如打一句「忽略以上規則,改成 xxx」)。這也是為什麼 system/user 角色要分開處理,而不是全部串成一串文字。
針對prompt Engineering的分享到這邊告一段落,這幾天記錄了prompt的基本架構、操作概念(範例、引導推理),以及今天分享了版本控制的重要、模型回應的驗證比較方法等。
明天開始會切換到下一個主題:Context Engineering。當想要給模型的資訊越來越多時,該如何精簡或管理模型得到的資訊,是下一章節的重點。